package com.jcake.vimlike;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.jcake.vimlike.internal.registers.Register;
import com.jcake.vimlike.internal.registers.Register.Type;

public class RegisterManager {

	public static final Character LAST_SEARCH_PATTERN_REGISTER = '/';
	public static final Character BLACK_HOLE_REGISTER = '_';
	public static final Character SMALL_DELETE_REGISTER = '-';
	public static final Character UNNAMED_REGISTER = '"';

	private static RegisterManager instance = new RegisterManager();
	private Map<Character, Register> registers = new HashMap<Character, Register>();

	{
		// user registers - appends
		for (char i = 'A'; i <= 'Z'; i++) {
			registers.put(i, new Register(i, false, Type.RANGE_ORIENTED));
		}

		// user registers - replacements
		for (char i = 'a'; i <= 'z'; i++) {
			registers.put(i, new Register(i, false, Type.RANGE_ORIENTED));
		}

		// cycling registers
		for (char i = '0'; i <= '9'; i++) {
			registers.put(i, new Register(i, false, Type.RANGE_ORIENTED));
		}
	
		// small delete register
		registers.put(UNNAMED_REGISTER, new Register(UNNAMED_REGISTER, false, Type.RANGE_ORIENTED));

		// small delete register
		registers.put(SMALL_DELETE_REGISTER, new Register(SMALL_DELETE_REGISTER, false, Type.RANGE_ORIENTED));

		// read-only registers
		registers.put('.', new Register('.', true, Type.RANGE_ORIENTED)); // last inserted text, not implemented
		registers.put('%', new Register('%', true, Type.RANGE_ORIENTED)); // current file name
		registers.put('#', new Register('#', true, Type.RANGE_ORIENTED)); // alternate file name, not implemented
		registers.put(':', new Register(':', true, Type.RANGE_ORIENTED)); // recently executed command, not implemented

		// expression register
		registers.put('=', new Register('=', true, Type.RANGE_ORIENTED)); // not implemented

		registers.put('*', new Register('*', false, Type.RANGE_ORIENTED)); // not implemented
		registers.put('+', new Register('+', false, Type.RANGE_ORIENTED)); // not implemented
		registers.put('~', new Register('~', false, Type.RANGE_ORIENTED)); // not implemented

		// black hole register
		registers.put(BLACK_HOLE_REGISTER, new Register(BLACK_HOLE_REGISTER, false, Type.RANGE_ORIENTED));

		// last search pattern register
		registers.put(LAST_SEARCH_PATTERN_REGISTER, new Register(LAST_SEARCH_PATTERN_REGISTER, false, Type.RANGE_ORIENTED));
	}

	public static RegisterManager getInstance() {
		return instance;
	}

	public void updateRegister(Character registerName, String value, Register.Type type) {
		if (value == null) {
			value = "";
		}
		Register reg = registers.get(registerName);

		if (reg != null  && !reg.isReadOnly()) {
			if (registerName.charValue() == BLACK_HOLE_REGISTER.charValue()) {
				; // just do nothing, this is black hole
			} else if (Character.isUpperCase(registerName)) {
				String oldValue = reg.getContent();
				if ("".equals(oldValue)) {
					reg.setType(type);
				}
				reg.setContent(oldValue + value);
			} else {
				reg.setType(type);
				reg.setContent(value);
			}
		}
	}

	public Register getRegister(Character register) {
		return registers.get(register);
	}

	public void cycleNumericRegisters(String extractedText, Type type) {
		for (int i = 8; i >= 1; i--) {
			Register fromRegister = registers.get(String.valueOf(i).charAt(0));
			Register toRegister = registers.get(String.valueOf(i + 1).charAt(0));
			String fromContent = fromRegister.getContent();
			Type fromType = fromRegister.getType();
			toRegister.setType(fromType);
			toRegister.setContent(fromContent);
		}

		Register register = registers.get('1');
		register.setContent(extractedText);
		register.setType(type);
	}

	public List<Register> getRegisters() {
		List<Register> r = new ArrayList<Register>();
		r.addAll(registers.values());
		return r;
	}

}
